package c2.advanced.business.base;

import c2.advanced.C2Advanced;
import c2.advanced.business.AdvancedBody;
import c2.advanced.business.common.CommonModule;
import c2.advanced.share.*;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

@Slf4j
public abstract class AdvancedModule<S extends KvData> {

    protected S status;

    protected abstract String getStatusKey();

    protected abstract AdvancedBody context();

    /**
     * 提供模块名
     */
    public abstract String getName();

    protected ApiFacade api() {
        return context().api;
    }

    protected TableFacade table() {
        return context().table;
    }

    protected RpcSuit rpc() {
        return context().rpc;
    }

    protected PlayFacade play() {
        return context().play;
    }

    protected abstract DbFacade _db();

    protected CommonModule common() {
        return context().common;
    }

    protected AdvancedSubModule[] getSubModules() {
        return new AdvancedSubModule[]{};
    }

    /**
     * 独立の初始化，不依赖于其他模块
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public void initIndependent(ModuleRequirements requirements) throws Exception {
        loadStatus();
        for (AdvancedSubModule sub : getSubModules()) {
            try {
                sub.setParent(this);
                sub.initIndependent(requirements, context());
            } catch (Exception e) {
                log.error("子模块({})initIndependent[独立初始化]失败!退出程序", sub.getClass(), e);
                C2Advanced.shutdown("sub-mod-initIndependent-fail");
            }
        }
    }

    /**
     * 依赖の初始化，此处可以对其他模块进行调用
     */
    @SuppressWarnings("rawtypes")
    public void initDependent() throws Exception {
        for (AdvancedSubModule sub : getSubModules()) {
            try {
                sub.initDependent();
            } catch (Exception e) {
                log.error("子模块({})initDependent[依赖其他模块的初始化]失败!退出程序", sub.getClass(), e);
                C2Advanced.shutdown("sub-mod-initDependent-fail");
            }
        }
    }

    protected S loadStatus() throws Exception {
        status = _db().kv.getByKey(getStatusKey(), getStatusClass());
        if (status == null) {
            status = getStatusClass().newInstance();
        }
        status.init(getStatusKey());
        return status;
    }

    protected Class<S> getStatusClass() {
        Type superclass = getClass().getGenericSuperclass();
        ParameterizedType parameterizedType;
        if (superclass instanceof ParameterizedType) {
            parameterizedType = (ParameterizedType) superclass;
            Type[] typeArray = parameterizedType.getActualTypeArguments();
            if (typeArray != null && typeArray.length > 0) {
                try{
                    return  (Class<S>) typeArray[0];
                }catch(Exception e){
                    log.error("{}类获取status class失败", getClass().getName(),e);
                }
            }
        }
        C2Advanced.shutdown("mod-getStatusClass-fail");
        return null;
    }

    private int tickCount;

    /**
     * 每秒被调用
     */
    public final void tick() throws Exception {
        tickCount++;
        if(getIntervalSeconds() <= 0) {
            throw new Exception("getIntervalSeconds()必须大于等于1");
        }
        if (tickCount % getIntervalSeconds() == 0) {
            onInterval();
        }
    }

    /**
     * 每N秒执行一次onInterval()
     */
    protected int getIntervalSeconds() {
        return 10;
    }

    public S saveStatus() {
        if (status == null) {
            log.warn("{} status为null", getName());
        }
        return context().dbBase().kv.save(status);
    }

    /**
     * 每N秒事件
     */
    protected void onInterval() throws Exception {
        for (AdvancedSubModule sub : getSubModules()) {
            try {
                sub.onInterval();
            } catch (Exception e) {
                log.error("组服子模块({})onInterval失败!", sub.getClass(), e);
            }
        }
    }

    public final void onShutdown() throws Exception {
        onShutdownBeforeSubModules();
        for (AdvancedSubModule sub : getSubModules()) {
            try {
                sub.onShutdown();
            } catch (Exception e) {
                log.error("子模块({})onShutdown异常", sub.getClass(), e);
            }
        }
        onShutdownAfterSubModules();
        saveStatus();
    }

    /**
     * 关闭时，在子模块之前所需执行的逻辑
     */
    protected void onShutdownBeforeSubModules() {
    }

    /**
     * 关闭时，在子模块之后所需执行的逻辑
     */
    protected void onShutdownAfterSubModules() {
    }

    public String code() {
        return context().getCode();
    }

}
